package com.example.android.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import com.example.android.synchronization.ThreadEvent;

public class Client
{
	private static Client instance = new Client();

	String serverIpAddress;
	int serverPort;

	Socket clientSocket;

	Sender sender;
	Thread senderThread;

	Receiver receiver;
	Thread receiverThread;
	
	ThreadEvent threadEvent = new ThreadEvent();

	private Client()
	{
	}

	public static Client getInstance()
	{
		return instance;
	}


	public void send(OutPacketType packetType, Object... objects)
	{
		StringBuilder packet = new StringBuilder();
		packet.append(packetType.getTranslation());
		for (Object object : objects)
		{
			packet.append(object.toString());
			packet.append(Constants.valSeparator);
		}
		sender.send(packet.toString());
	}

	public void close()
	{
		try
		{
			sender.close();
			receiver.close();
			clientSocket.close();
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void connect(String serverIpAddress, int serverPort)
	{
		this.serverIpAddress = serverIpAddress;
		this.serverPort = serverPort;
		
		InetAddress serverAddr;
		try
		{
			serverAddr = InetAddress.getByName(serverIpAddress);
			clientSocket = new Socket(serverAddr, serverPort);
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		sender = new Sender();
		senderThread = new Thread(sender);
		senderThread.start();
		threadEvent.await();
		receiver = new Receiver();
		receiverThread = new Thread(receiver);
		receiverThread.start();
		threadEvent.await();
	}

	class Sender implements Runnable
	{
		ThreadEvent resultsReady = new ThreadEvent();
		String resultPacket;
		PrintWriter out;
		boolean off = false;

		@Override
		public void run()
		{
			System.err.println("Starting Sender Thread");

			try
			{
				out = new PrintWriter(clientSocket.getOutputStream(), true);
				threadEvent.signal();
			} catch (IOException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			while (true)
			{
				resultsReady.await();
				if (off)
					break;
				
				System.err.println("RRR:  "+resultPacket);
				out.println(resultPacket);
			}
			
			System.err.println("Closing Sender Thread");
		}

		public void send(String resultPacket)
		{
			this.resultPacket = resultPacket;
			resultsReady.signal();
		}

		public void close()
		{
			off = true;
			
			resultsReady.signal();
			out.close();
		}
	}

	class Receiver implements Runnable
	{
		BufferedReader in;
		boolean off = false;

		@Override
		public void run()
		{
			System.err.println("Starting Receiver Thread");

			try
			{
				in = new BufferedReader(new InputStreamReader(
						clientSocket.getInputStream()));
				threadEvent.signal();

				while (true)
				{
					if (off)
						break;
					String packet = in.readLine();
					if(packet != null)
						{
						ActionFactory.execute(packet);
						}
				}
			} catch (IOException e)
			{
				e.printStackTrace();
			}
			
			System.err.println("Closing Receiver Thread");
		}

		public void close()
		{
			off = true;
			try
			{
				in.close();
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
}
